package com.xzzz.common.feign;

import com.xzzz.common.base.BaseProperties;
import com.xzzz.common.base.exception.AbstractExceptionAdvice;
import com.xzzz.common.base.pojo.R;
import com.xzzz.common.base.pojo.RCode;
import feign.FeignException;
import feign.RetryableException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.net.SocketTimeoutException;

/**
 * 用于处理 feign 错误的异常增强, 此类的 {@link Order} 需要小于 GlobalExceptionHandler
 *
 * @author xzzz
 */
@Slf4j
@Order(-1000)
@RestControllerAdvice
public class ExceptionAdviceByFeign extends AbstractExceptionAdvice {

    public ExceptionAdviceByFeign(BaseProperties baseProperties) {
        super(baseProperties);
    }

    @ExceptionHandler(FeignException.NotFound.class)
    public R<?> handleException(FeignException.NotFound notFound) {
        printExLog(notFound, RCode.NOT_FOUND_FEIGN.getMsg(), true);
        return R.fault(
                RCode.NOT_FOUND_FEIGN.getCode(),
                RCode.NOT_FOUND_FEIGN.getMsg(),
                notFound.getMessage()
        );
    }

    @ExceptionHandler(FeignException.ServiceUnavailable.class)
    public R<?> handleException(FeignException.ServiceUnavailable serviceUnavailable) {
        String url = serviceUnavailable.request().url();
        printExLog(serviceUnavailable, RCode.SERVER_UNAVAILABLE_FEIGN.getMsg(), true);
        return R.fault(
                RCode.SERVER_UNAVAILABLE_FEIGN.getCode(),
                String.format("服务方 [%s] 暂时无法处理请求, 请稍后再试。", url),
                serviceUnavailable.getMessage()
        );
    }

    @ExceptionHandler(RetryableException.class)
    public R<?> handleException(RetryableException retryable) {
        if (retryable.getCause() instanceof SocketTimeoutException) {
            printExLog(retryable, RCode.SERVER_RETRYABLE_FEIGN.getMsg());
            return R.fault(
                    RCode.SERVER_RETRYABLE_FEIGN.getCode(),
                    RCode.SERVER_RETRYABLE_FEIGN.getMsg(),
                    retryable.getMessage()
            );
        }

        printExLog(retryable, RCode.SERVER_UNAVAILABLE_FEIGN.getMsg(), true);
        return R.fault(
                RCode.SERVER_UNAVAILABLE_FEIGN.getCode(),
                RCode.SERVER_UNAVAILABLE_FEIGN.getMsg(),
                retryable.getMessage()
        );
    }

}
